home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS09.ADF / MicroEMACS / main.c < prev    next >
C/C++ Source or Header  |  1986-05-22  |  25KB  |  651 lines

  1. /*
  2.  * This program is in public domain; written by Dave G. Conroy.
  3.  * This file contains the main driving routine, and some keyboard processing
  4.  * code, for the MicroEMACS screen editor.
  5.  *
  6.  * REVISION HISTORY:
  7.  *
  8.  * 1.0  Steve Wilhite, 30-Nov-85
  9.  *      - Removed the old LK201 and VT100 logic. Added code to support the
  10.  *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  11.  *        1 Console In ROM INT. See "rainbow.h" for the function key definitions.
  12.  *
  13.  * 2.0  George Jones, 12-Dec-85
  14.  *      - Ported to Amiga.
  15.  */
  16. #include        <stdio.h>
  17. #include        "ed.h"
  18.  
  19. #if     VMS
  20. #include        <ssdef.h>
  21. #define GOOD    (SS$_NORMAL)
  22. #endif
  23.  
  24. #ifndef GOOD
  25. #define GOOD    0
  26. #endif
  27.  
  28. long    startLock;
  29. long    newLock;                        /* used if started from WB      */
  30. short    currow;                /* Working cursor row           */
  31. short    curcol;                /* Working cursor column        */
  32. short   fillcol;            /* Current fill column          */
  33. short   wordwrap = FALSE;        /* Word wrap flag        */
  34. short    autoindent = TRUE;        /* Auto indentation flag    */
  35. short   LeftMargin = 0;                 /* Left margin amount           */
  36. int     thisflag;                       /* Flags, this command          */
  37. int     lastflag;                       /* Flags, last command          */
  38. int     curgoal;                        /* Goal column                  */
  39. BUFFER  *curbp;                         /* Current buffer               */
  40. WINDOW  *curwp;                         /* Current window               */
  41. BUFFER  *bheadp;                        /* BUFFER listhead              */
  42. WINDOW  *wheadp;                        /* WINDOW listhead              */
  43. BUFFER  *blistp;                        /* Buffer list BUFFER           */
  44. BUFFER  *prev_bp;                       /* Previous Buffer               */
  45. short   kbdm[NKBDM] = {CTLX|')'};       /* Macro                        */
  46. short   *kbdmip;                        /* Input  for above             */
  47. short   *kbdmop;                        /* Output for above             */
  48. char    pat[NPAT];                      /* Pattern                      */
  49.  
  50. typedef struct  {
  51.         short   k_code;                 /* Key code                     */
  52.         int     (*k_fp)();              /* Routine to handle it         */
  53. }       KEYTAB;
  54.  
  55. extern  int     ctrlg();                /* Abort out of things          */
  56. extern  int     quit();                 /* Quit                         */
  57. extern  int     ctlxlp();               /* Begin macro                  */
  58. extern  int     ctlxrp();               /* End macro                    */
  59. extern  int     ctlxe();                /* Execute macro                */
  60. extern  int     fileread();             /* Get a file, read only        */
  61. extern  int     filevisit();            /* Get a file, read write       */
  62. extern  int     filewrite();            /* Write a file                 */
  63. extern  int     filesave();             /* Save current file            */
  64. extern  int     filename();             /* Adjust file name             */
  65. extern    int    fileyank();        /* Yank buffer to a file    */
  66. extern  int     getccol();              /* Get current column           */
  67. extern  int     gotobol();              /* Move to start of line        */
  68. extern  int     forwchar();             /* Move forward by characters   */
  69. extern  int     gotoeol();              /* Move to end of line          */
  70. extern  int     backchar();             /* Move backward by characters  */
  71. extern  int     forwline();             /* Move forward by lines        */
  72. extern  int     backline();             /* Move backward by lines       */
  73. extern  int     forwpage();             /* Move forward by pages        */
  74. extern  int     backpage();             /* Move backward by pages       */
  75. extern  int     gotobob();              /* Move to start of buffer      */
  76. extern  int     gotoeob();              /* Move to end of buffer        */
  77. extern  int     setfillcol();           /* Set fill column.             */
  78. extern    int    toggleautoindent();    /* Toggle auto indentation    */
  79. extern  int     togglewordwrap();       /* Toggle word wrap        */
  80. extern  int     setmark();              /* Set mark                     */
  81. extern  int     swapmark();             /* Swap "." and mark            */
  82. extern  int     forwsearch();           /* Search forward               */
  83. extern  int     backsearch();           /* Search backwards             */
  84. extern  int     qreplace();             /* Query Replace        */
  85. extern  int     showcpos();             /* Show the cursor position     */
  86. extern  int     nextwind();             /* Move to the next window      */
  87. extern  int     prevwind();             /* Move to the previous window  */
  88. extern  int     onlywind();             /* Make current window only one */
  89. extern  int     splitwind();            /* Split current window         */
  90. extern  int     mvdnwind();             /* Move window down             */
  91. extern  int     mvupwind();             /* Move window up               */
  92. extern    int    moveline();        /* Move to a line number     */
  93. extern  int     enlargewind();          /* Enlarge display window.      */
  94. extern  int     shrinkwind();           /* Shrink window.               */
  95. extern  int     listbuffers();          /* Display list of buffers      */
  96. extern  int     usebuffer();            /* Switch a window to a buffer  */
  97. extern  int     killbuffer();           /* Make a buffer go away.       */
  98. extern  int     reposition();           /* Reposition window            */
  99. extern  int     refresh();              /* Refresh the screen           */
  100. extern  int     twiddle();              /* Twiddle characters           */
  101. extern  int     tab();                  /* Insert tab                   */
  102. extern  int     newline();              /* Insert CR-LF                 */
  103. extern  int     indent();               /* Insert CR-LF, then indent    */
  104. extern  int     openline();             /* Open up a blank line         */
  105. extern  int     deblank();              /* Delete blank lines           */
  106. extern  int     quote();                /* Insert literal               */
  107. extern  int     backword();             /* Backup by words              */
  108. extern  int     forwword();             /* Advance by words             */
  109. extern  int     forwdel();              /* Forward delete               */
  110. extern  int     backdel();              /* Backward delete              */
  111. extern  int     kill();                 /* Kill forward                 */
  112. extern  int     yank();                 /* Yank back from killbuffer.   */
  113. extern  int     upperword();            /* Upper case word.             */
  114. extern  int     lowerword();            /* Lower case word.             */
  115. extern  int     upperregion();          /* Upper case region.           */
  116. extern  int     lowerregion();          /* Lower case region.           */
  117. extern  int     capword();              /* Initial capitalize word.     */
  118. extern  int     delfword();             /* Delete forward word.         */
  119. extern  int     delbword();             /* Delete backward word.        */
  120. extern  int     killregion();           /* Kill region.                 */
  121. extern  int     copyregion();           /* Copy region to kill buffer.  */
  122. extern  int     spawncli();             /* Run CLI in a subjob.         */
  123. extern  int     spawn();                /* Run a command in a subjob.   */
  124. extern  int     quickexit();            /* low keystroke style exit.    */
  125. extern    int    parafill();        /* fill paragraph */
  126.  
  127. /*
  128.  * Command table.
  129.  * This table  is *roughly* in ASCII order, left to right across the
  130.  * characters of the command. This expains the funny location of the
  131.  * control-X commands.
  132.  */
  133. KEYTAB  keytab[] = {
  134.         CTRL|'@',               &setmark,
  135.         CTRL|'A',               &gotobol,
  136.         CTRL|'B',               &backchar,
  137.         CTRL|'C',               &spawncli,      /* Run CLI in subjob.   */
  138.         CTRL|'D',               &forwdel,
  139.         CTRL|'E',               &gotoeol,
  140.         CTRL|'F',               &forwchar,
  141.         CTRL|'G',               &ctrlg,
  142.         CTRL|'H',               &backdel,
  143.         CTRL|'I',               &tab,
  144.         CTRL|'J',               &indent,
  145.         CTRL|'K',               &kill,
  146.         CTRL|'L',               &refresh,
  147.         CTRL|'M',               &indent,
  148.         CTRL|'N',               &forwline,
  149.         CTRL|'O',               &openline,
  150.         CTRL|'P',               &backline,
  151.         CTRL|'Q',               "e,         /* Often unreachable    */
  152.         CTRL|'R',               &backsearch,
  153.         CTRL|'S',               &forwsearch,    /* Often unreachable    */
  154.         CTRL|'T',               &twiddle,
  155.         CTRL|'V',               &forwpage,
  156.         CTRL|'W',               &killregion,
  157.         CTRL|'Y',               &yank,
  158.         CTRL|'Z',               &quickexit,     /* quick save and exit  */
  159.         CTLX|CTRL|'B',          &listbuffers,
  160.         CTLX|CTRL|'C',          &quit,          /* Hard quit.           */
  161. /*        CTLX|CTRL|'F',          &filename,*/
  162.         CTLX|CTRL|'F',          &filevisit,
  163.         CTLX|CTRL|'L',          &lowerregion,
  164.         CTLX|CTRL|'O',          &deblank,
  165.         CTLX|CTRL|'N',          &mvdnwind,
  166.         CTLX|CTRL|'P',          &mvupwind,
  167.         CTLX|CTRL|'R',          &fileread,
  168.         CTLX|CTRL|'S',          &filesave,      /* Often unreachable    */
  169.         CTLX|CTRL|'U',          &upperregion,
  170.         CTLX|CTRL|'V',          &filevisit,
  171.         CTLX|CTRL|'W',          &filewrite,
  172.         CTLX|CTRL|'X',          &swapmark,
  173.         CTLX|CTRL|'Z',          &shrinkwind,
  174.         CTLX|'!',               &spawn,         /* Run 1 command.       */
  175.         CTLX|'=',               &showcpos,
  176.         CTLX|'(',               &ctlxlp,
  177.         CTLX|')',               &ctlxrp,
  178.         CTLX|'1',               &onlywind,
  179.         CTLX|'2',               &splitwind,
  180.         CTLX|'B',               &usebuffer,
  181.         CTLX|'E',               &ctlxe,
  182.         CTLX|'F',               &setfillcol,
  183.     CTLX|'I',        &toggleautoindent,
  184.         CTLX|'K',               &killbuffer,
  185.         CTLX|'N',               &nextwind,
  186.         CTLX|'P',               &prevwind,
  187.         CTLX|'T',               &togglewordwrap,
  188.         CTLX|'Z',               &enlargewind,
  189.         META|CTRL|'H',          &delbword,
  190.         META|'!',               &reposition,
  191.         META|'.',               &setmark,
  192.         META|'>',               &gotoeob,
  193.         META|'<',               &gotobob,
  194.         META|'B',               &backword,
  195.         META|'C',               &capword,
  196.         META|'D',               &delfword,
  197.         META|'F',               &forwword,
  198.         META|'L',               &lowerword,
  199.     META|'M',        &moveline,
  200.         META|'Q',               ¶fill,
  201.         META|'U',               &upperword,
  202.         META|'V',               &backpage,
  203.         META|'W',               ©region,
  204.     META|'Y',        &fileyank,
  205.     META|'%',        &qreplace,
  206.         META|0x7F,              &delbword,
  207.         0x7F,                   &backdel
  208. };
  209.  
  210. #define NKEYTAB (sizeof(keytab)/sizeof(keytab[0]))
  211.  
  212.  
  213. #if RAINBOW
  214.  
  215. #include "rainbow.h"
  216.  
  217. /*
  218.  * Mapping table from the LK201 function keys to the internal EMACS character.
  219.  */
  220.  
  221. short lk_map[][2] = {
  222.         Up_Key,                         CTRL+'P',
  223.         Down_Key,                       CTRL+'N',
  224.         Left_Key,                       CTRL+'B',
  225.         Right_Key,                      CTRL+'F',
  226.         Shift+Left_Key,                 META+'B',
  227.         Shift+Right_Key,                META+'F',
  228.         Control+Left_Key,               CTRL+'A',
  229.         Control+Right_Key,              CTRL+'E',
  230.         Prev_Scr_Key,                   META+'V',
  231.         Next_Scr_Key,                   CTRL+'V',
  232.         Shift+Up_Key,                   META+'<',
  233.         Shift+Down_Key,                 META+'>',
  234.         Cancel_Key,                     CTRL+'G',
  235.         Find_Key,                       CTRL+'S',
  236.         Shift+Find_Key,                 CTRL+'R',
  237.         Insert_Key,                     CTRL+'Y',
  238.         Options_Key,                    CTRL+'D',
  239.         Shift+Options_Key,              META+'D',
  240.         Remove_Key,                     CTRL+'W',
  241.         Shift+Remove_Key,               META+'W',
  242.         Select_Key,                     CTRL+'@',
  243.         Shift+Select_Key,               CTLX+CTRL+'X',
  244.         Interrupt_Key,                  CTRL+'U',
  245.         Keypad_PF2,                     META+'L',
  246.         Keypad_PF3,                     META+'C',
  247.         Keypad_PF4,                     META+'U',
  248.         Shift+Keypad_PF2,               CTLX+CTRL+'L',
  249.         Shift+Keypad_PF4,               CTLX+CTRL+'U',
  250.         Keypad_1,                       CTLX+'1',
  251.         Keypad_2,                       CTLX+'2',
  252.         Do_Key,                         CTLX+'E',
  253.         Keypad_4,                       CTLX+CTRL+'B',
  254.         Keypad_5,                       CTLX+'B',
  255.         Keypad_6,                       CTLX+'K',
  256.         Resume_Key,                     META+'!',
  257.         Control+Next_Scr_Key,           CTLX+'N',
  258.         Control+Prev_Scr_Key,           CTLX+'P',
  259.         Control+Up_Key,                 CTLX+CTRL+'P',
  260.         Control+Down_Key,               CTLX+CTRL+'N',
  261.         Help_Key,                       CTLX+'=',
  262.         Shift+Do_Key,                   CTLX+'(',
  263.         Control+Do_Key,                 CTLX+')',
  264.         Keypad_0,                       CTLX+'Z',
  265.         Shift+Keypad_0,                 CTLX+CTRL+'Z',
  266.         Main_Scr_Key,                   CTRL+'C',
  267.         Keypad_Enter,                   CTLX+'!',
  268.         Exit_Key,                       CTLX+CTRL+'C',
  269.         Shift+Exit_Key,                 CTRL+'Z'
  270.         };
  271.  
  272. #define lk_map_size     (sizeof(lk_map)/2)
  273.  
  274. #endif
  275.  
  276. #if AMIGA
  277. #define CSI 0x9B
  278. #include <exec/types.h>
  279. #include <workbench/startup.h>
  280. #endif
  281.  
  282. main(argc, argv)
  283. char    *argv[];
  284. {
  285.         register int    c;
  286.         register int    f;
  287.         register int    n;
  288.     struct WBStartup *WBenchMsg;
  289.     struct WBArg     *arg;
  290.     char            *infile;
  291.         char            bname[NBUFN];
  292.     int    mflag;
  293.  
  294.         WBenchMsg = argv;                       /* Manx method */
  295.         strcpy(bname, "main");                  /* Work out the name of */
  296.         if (argc > 1)                           /* the default buffer.  */
  297.             infile = argv[1];
  298.     else if ( (argc == 0) && (WBenchMsg->sm_NumArgs > 1) )
  299.         {
  300.         arg = WBenchMsg->sm_ArgList;
  301.         arg++;
  302.         newLock   = arg->wa_Lock;
  303.         startLock = CurrentDir( newLock );
  304.         infile = arg->wa_Name;
  305.         }
  306.     else
  307.         infile = NULL;
  308.         
  309.     if ( infile )
  310.         makename( bname, infile );
  311.         edinit(bname);                          /* Buffers, windows.    */
  312.         vtinit();                               /* Displays.            */
  313.     fillcol = term.t_ncol -2;
  314.  
  315.         if ( infile ) {
  316.                 update();                       /* You have to update   */
  317.                 readin( infile );               /* in case "[New file]" */
  318.         }
  319.         lastflag = 0;                           /* Fake last flags.     */
  320. loop:
  321.         update();                               /* Fix up the screen    */
  322.         c = getkey();
  323.         if (mpresf != FALSE) {
  324.                 mlerase();
  325.                 update();
  326. #if AMIGA
  327.         /* the its action for space interacts badly with mouse
  328.          * interaction, so we skip it for the amiga.
  329.          */
  330. #else
  331.                 if (c == ' ')                   /* ITS EMACS does this  */
  332.                         goto loop;
  333. #endif
  334.         }
  335.         f = FALSE;
  336.         n = 1;
  337.         if (c == (CTRL|'U')) {                  /* ^U, start argument   */
  338.                 f = TRUE;
  339.                 n = 4;                          /* with argument of 4 */
  340.                 mflag = 0;                      /* that can be discarded. */
  341.                 mlwrite("Repeat Count: 4");
  342.                 while (((c=getkey()) >='0' && c<='9') || c==(CTRL|'U')
  343.         || c=='-') {
  344.                         if (c == (CTRL|'U'))
  345.                                 n = n*4;
  346.                         /*
  347.                          * If dash, and start of argument string, set arg.
  348.                          * to -1.  Otherwise, insert it.
  349.                          */
  350.                         else if (c == '-') {
  351.                                 if (mflag)
  352.                                         break;
  353.                                 n = 0;
  354.                                 mflag = -1;
  355.                         }
  356.                         /*
  357.                          * If first digit entered, replace previous argument
  358.                          * with digit and set sign.  Otherwise, append to arg.
  359.                          */
  360.                         else {
  361.                                 if (!mflag) {
  362.                                         n = 0;
  363.                                         mflag = 1;
  364.                                 }
  365.                                 n = 10*n + c - '0';
  366.                         }
  367.                         mlwrite("Repeat Count: %d", (mflag >=0) ? n : (n ? -n : -1));
  368.                 }
  369.                 /*
  370.                  * Make arguments preceded by a minus sign negative and change
  371.                  * the special argument "^U -" to an effective "^U -1".
  372.                  */
  373.                 if (mflag == -1) {
  374.                         if (n == 0)
  375.                                 n++;
  376.                         n = -n;
  377.                 }
  378.         }
  379.         if (c == (CTRL|'X'))                    /* ^X is a prefix       */
  380.                 c = CTLX | getctl();
  381. #if AMIGA
  382.     if( (c & 0xFF) == CSI) 
  383.         {
  384.         mouse_handle_event( f, n);
  385.         goto loop;
  386.         }
  387. #endif
  388.         if (kbdmip != NULL) {                   /* Save macro strokes.  */
  389.                 if ( c != (CTLX|')') && kbdmip > &kbdm[NKBDM-6] ) {
  390.                         ctrlg(FALSE, 0);
  391.                         goto loop;
  392.                 }
  393.                 if (f != FALSE) {
  394.                         *kbdmip++ = (CTRL|'U');
  395.                         *kbdmip++ = n;
  396.                 }
  397.                 *kbdmip++ = c;
  398.         }
  399.         execute(c, f, n);                       /* Do it.               */
  400.         goto loop;
  401. }
  402.  
  403. /*
  404.  * Initialize all of the buffers and windows. The buffer name is passed down
  405.  * as an argument, because the main routine may have been told to read in a
  406.  * file by default, and we want the buffer name to be right.
  407.  */
  408. edinit(bname)
  409. char    bname[];
  410. {
  411.         register BUFFER *bp;
  412.         register WINDOW *wp;
  413.  
  414.         bp = bfind(bname, TRUE, 0);             /* First buffer         */
  415.         blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer   */
  416.         wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  417.         if (bp==NULL || wp==NULL || blistp==NULL)
  418.                 exit(1);
  419.         curbp  = bp;                            /* Make this current    */
  420.         wheadp = wp;
  421.         curwp  = wp;
  422.         wp->w_wndp  = NULL;                     /* Initialize window    */
  423.         wp->w_bufp  = bp;
  424.         bp->b_nwnd  = 1;                        /* Displayed.           */
  425.         wp->w_linep = bp->b_linep;
  426.         wp->w_dotp  = bp->b_linep;
  427.         wp->w_doto  = 0;
  428.         wp->w_markp = NULL;
  429.         wp->w_marko = 0;
  430.         wp->w_toprow = 0;
  431.         wp->w_ntrows = term.t_nrow-1;           /* "-1" for mode line.  */
  432.         wp->w_force = 0;
  433.         wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  434. }
  435.         
  436. /*
  437.  * This is the general command execution routine. It handles the fake binding
  438.  * of all the keys to "self-insert". It also clears out the "thisflag" word,
  439.  * and arranges to move it to the "lastflag", so that the next command can
  440.  * look at it. Return the status of command.
  441.  */
  442. execute(c, f, n)
  443. {
  444.         register KEYTAB *ktp;
  445.         register int    status;
  446.  
  447.         if ((c>=0x20 && c<=0x7E)                /* Self inserting.      */
  448.         ||  (c>=0xA0 && c<=0xFE)) {
  449.         /*
  450.          * If word wrap is true, the argument is non-
  451.          * negative, and we are now past fill column, perform word wrap.
  452.              */
  453.             if (wordwrap && n>=0 && getccol(FALSE) > fillcol)
  454.                 wrapword();
  455.  
  456.                 if (n <= 0) {                   /* Fenceposts.          */
  457.                         lastflag = 0;
  458.                         return (n<0 ? FALSE : TRUE);
  459.                 }
  460.                 thisflag = 0;                   /* For the future.      */
  461.                 status   = linsert(n, c);
  462.                 lastflag = thisflag;
  463.                 return (status);
  464.         }
  465.  
  466.         ktp = &keytab[0];                       /* Look in key table.   */
  467.         while (ktp < &keytab[NKEYTAB]) {
  468.                 if (ktp->k_code == c) {
  469.                         thisflag = 0;
  470.                         status   = (*ktp->k_fp)(f, n);
  471.                         lastflag = thisflag;
  472.                         return (status);
  473.                 }
  474.                 ++ktp;
  475.         }
  476.  
  477.         lastflag = 0;                           /* Fake last flags.     */
  478.         return (FALSE);
  479. }
  480.  
  481. /*
  482.  * Read in a key.
  483.  * Do the standard keyboard preprocessing. Convert the keys to the internal
  484.  * character set.
  485.  */
  486. getkey()
  487. {
  488.         register int    c;
  489.  
  490.         c = (*term.t_getchar)();
  491.  
  492. #if RAINBOW
  493.  
  494.         if (c & Function_Key)
  495.                 {
  496.                 int i;
  497.  
  498.                 for (i = 0; i < lk_map_size; i++)
  499.                         if (c == lk_map[i][0])
  500.                                 return lk_map[i][1];
  501.                 }
  502.         else if (c == Shift + 015) return CTRL | 'J';
  503.         else if (c == Shift + 0x7F) return META | 0x7F;
  504. #endif
  505.  
  506.         if (c == METACH) {                      /* Apply M- prefix      */
  507.                 c = getctl();
  508.                 return (META | c);
  509.         }
  510.  
  511.         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  512.                 c = CTRL | (c+'@');
  513.  
  514. #if AMIGA
  515.     else if(( c & 0x80) && ((c&0xFF) != CSI)) { /* Meta-shifted char */
  516.         c &= 0x7F;
  517.             if (c>='a' && c<='z')        /* Force to upper       */
  518.                     c -= 0x20;
  519.         c |= META;
  520.     }
  521. #endif
  522.         return (c);
  523. }
  524.  
  525. /*
  526.  * Get a key.
  527.  * Apply control modifications to the read key.
  528.  */
  529. getctl()
  530. {
  531.         register int    c;
  532.  
  533.         c = (*term.t_getchar)();
  534.         if (c>='a' && c<='z')                   /* Force to upper       */
  535.                 c -= 0x20;
  536.         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  537.                 c = CTRL | (c+'@');
  538.         return (c);
  539. }
  540.  
  541. /*
  542.  * Fancy quit command, as implemented by Norm. If the current buffer has
  543.  * changed do a write current buffer and exit emacs, otherwise simply exit.
  544.  */
  545. quickexit(f, n)
  546. {
  547.         if ((curbp->b_flag&BFCHG) != 0          /* Changed.             */
  548.         && (curbp->b_flag&BFTEMP) == 0)         /* Real.                */
  549.                 filesave(f, n);
  550.         quit(f, n);                             /* conditionally quit   */
  551. }
  552.  
  553. /*
  554.  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  555.  * has been changed and not written out. Normally bound to "C-X C-C".
  556.  */
  557. quit(f, n)
  558. {
  559.         register int    s;
  560.  
  561.         if (f != FALSE                          /* Argument forces it.  */
  562.         || anycb() == FALSE                     /* All buffers clean.   */
  563.         || (s=mlyesno("Modified buffers exist.  Quit")) == TRUE) {
  564.                            /* User says it's OK.   */
  565.                 vttidy();
  566.                 exit(GOOD);
  567.         }
  568.         return (s);
  569. }
  570.  
  571. /*
  572.  * Begin a keyboard macro.
  573.  * Error if not at the top level in keyboard processing. Set up variables and
  574.  * return.
  575.  */
  576. ctlxlp(f, n)
  577. {
  578.         if (kbdmip!=NULL || kbdmop!=NULL) {
  579.                 mlwrite("Not now");
  580.                 return (FALSE);
  581.         }
  582.         mlwrite("[Start macro]");
  583.         kbdmip = &kbdm[0];
  584.         return (TRUE);
  585. }
  586.  
  587. /*
  588.  * End keyboard macro. Check for the same limit conditions as the above
  589.  * routine. Set up the variables and return to the caller.
  590.  */
  591. ctlxrp(f, n)
  592. {
  593.         if (kbdmip == NULL) {
  594.                 mlwrite("Not now");
  595.                 return (FALSE);
  596.         }
  597.         mlwrite("[End macro]");
  598.         kbdmip = NULL;
  599.         return (TRUE);
  600. }
  601.  
  602. /*
  603.  * Execute a macro.
  604.  * The command argument is the number of times to loop. Quit as soon as a
  605.  * command gets an error. Return TRUE if all ok, else FALSE.
  606.  */
  607. ctlxe(f, n)
  608. {
  609.         register int    c;
  610.         register int    af;
  611.         register int    an;
  612.         register int    s;
  613.  
  614.         if (kbdmip!=NULL || kbdmop!=NULL) {
  615.                 mlwrite("Not now");
  616.                 return (FALSE);
  617.         }
  618.         if (n <= 0) 
  619.                 return (TRUE);
  620.         do {
  621.                 kbdmop = &kbdm[0];
  622.                 do {
  623.                         af = FALSE;
  624.                         an = 1;
  625.                         if ((c = *kbdmop++) == (CTRL|'U')) {
  626.                                 af = TRUE;
  627.                                 an = *kbdmop++;
  628.                                 c  = *kbdmop++;
  629.                         }
  630.                         s = TRUE;
  631.                 } while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
  632.                 kbdmop = NULL;
  633.         } while (s==TRUE && --n);
  634.         return (s);
  635. }
  636.  
  637. /*
  638.  * Abort.
  639.  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  640.  * Sometimes called as a routine, to do general aborting of stuff.
  641.  */
  642. ctrlg(f, n)
  643. {
  644.         (*term.t_beep)();
  645.         if (kbdmip != NULL) {
  646.                 kbdm[0] = (CTLX|')');
  647.                 kbdmip  = NULL;
  648.         }
  649.         return (ABORT);
  650. }
  651.